<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>井字棋 - 游戏空间</title>
    <script src="https://cdn.tailwindcss.com"></script>
    <link href="https://cdn.jsdelivr.net/npm/font-awesome@4.7.0/css/font-awesome.min.css" rel="stylesheet">
    <script src="/static/common.js"></script>
    <style>
        body {
            background: linear-gradient(135deg, #e0e7ff 0%, #f8fafc 100%);
        }
        .modern-card {
            border-radius: 1.5rem;
            box-shadow: 0 4px 32px 0 #6366f133;
            background: #fff;
        }
        .player-card {
            background: #fff;
            border-radius: 1rem;
            padding: 1rem;
            text-align: center;
            min-width: 140px;
            box-shadow: 0 2px 12px rgba(99, 102, 241, 0.1);
            transition: all 0.3s ease;
        }
        .player-card.ready {
            border: 2px solid #4ade80;
        }
        .player-card.not-ready {
            border: 2px solid #e5e7eb;
        }
        .player-card .avatar {
            width: 48px;
            height: 48px;
            border-radius: 50%;
            background: #f3f4f6;
            margin: 0 auto 0.5rem;
            display: flex;
            align-items: center;
            justify-content: center;
            font-size: 1.5rem;
            color: #6366f1;
        }
        .player-card .name {
            font-weight: 600;
            color: #1f2937;
            margin-bottom: 0.25rem;
            font-size: 0.9rem;
        }
        .player-card .status {
            font-size: 0.75rem;
            color: #6b7280;
        }
        .player-card .status.ready {
            color: #4ade80;
        }
        /* 自定义弹窗样式 */
        #back-modal {
            display: none;
            position: fixed;
            z-index: 1000;
            left: 0; top: 0; right: 0; bottom: 0;
            background: rgba(0,0,0,0.3);
            align-items: center;
            justify-content: center;
        }
        #back-modal .modal-content {
            background: #fff;
            border-radius: 1rem;
            padding: 2rem 2.5rem;
            box-shadow: 0 8px 32px 0 #6366f155;
            text-align: center;
            min-width: 240px;
        }
        #back-modal .modal-btn {
            margin: 0 0.5rem;
            padding: 0.5rem 1.5rem;
            border-radius: 999px;
            font-weight: bold;
            background: linear-gradient(90deg, #6366f1 0%, #818cf8 100%);
            color: #fff;
            border: none;
            cursor: pointer;
            transition: background 0.2s, transform 0.2s;
        }
        #back-modal .modal-btn:hover {
            background: linear-gradient(90deg, #818cf8 0%, #6366f1 100%);
            transform: scale(1.05);
        }
    </style>
</head>
<body class="font-sans text-dark min-h-screen flex flex-col">
    <div id="game-header" style="display:flex;align-items:center;justify-content:space-between;padding:8px 16px;">
        <span id="room-user-count" class="text-gray-700 text-sm"></span>
    </div>
    <header class="modern-nav text-white shadow-md p-4 flex flex-col items-center bg-indigo-600 relative">
        <div class="flex items-center mb-2">
            <span class="text-xl font-bold ml-4">井字棋</span>
        </div>
        <div id="user-info" class="text-lg font-bold text-indigo-100 mb-1"></div>
        <div id="score-info" class="flex gap-4 text-base font-semibold"></div>
        <div id="game-tip" class="text-sm bg-indigo-100 text-indigo-700 rounded px-2 py-1 mt-1"></div>
        <div class="flex items-center absolute right-4 top-4">
            <button id="match-btn" class="bg-white text-indigo-700 px-4 py-1 rounded shadow hover:bg-indigo-100 transition">匹配</button>
            <button id="ready-btn" class="ml-2 modern-btn px-4 py-1">准备</button>
            <button id="delete-room-btn" class="ml-2 bg-red-500 text-white px-4 py-1 rounded shadow hover:bg-red-600 transition hidden">删除房间</button>
            <button id="back-select-btn" class="ml-2 modern-btn px-4 py-1">返回大厅</button>
        </div>
    </header>
    <main class="flex-grow flex flex-col items-center justify-center">
        <div id="game-area" class="mt-8">
            <h2 class="text-lg font-bold mb-4 text-primary flex items-center"><i class="fa fa-th mr-2"></i>井字棋对战</h2>
            <div id="player-list" class="flex justify-between w-full max-w-xs mb-4 gap-4">
                <div class="player-card not-ready" id="player1-card">
                    <div class="avatar">
                        <i class="fa fa-user"></i>
                    </div>
                    <div class="name" id="player1-name">等待加入...</div>
                    <div class="status" id="player1-status">未准备</div>
                </div>
                <div class="player-card not-ready" id="player2-card">
                    <div class="avatar">
                        <i class="fa fa-user"></i>
                    </div>
                    <div class="name" id="player2-name">等待加入...</div>
                    <div class="status" id="player2-status">未准备</div>
                </div>
            </div>
            <div class="mt-4 flex flex-col items-center">
                <button id="start-btn" class="ml-2 modern-btn px-4 py-1 hidden">开始游戏</button>
                <button id="restart-btn" class="modern-btn px-6 py-2 mt-2 hidden">重新开始</button>
            </div>
            <canvas id="tictactoe-canvas" width="300" height="300" tabindex="0" class="mb-4"></canvas>
        </div>
    </main>
    <!-- 自定义返回弹窗 -->
    <div id="back-modal">
        <div class="modal-content">
            <div class="text-lg font-bold mb-4">请选择返回位置</div>
            <button class="modal-btn" id="to-game-lobby">返回游戏大厅</button>
            <button class="modal-btn" id="to-chat-lobby">返回聊天大厅</button>
            <div class="mt-4"><button class="text-gray-400 hover:text-primary" id="close-modal">取消</button></div>
        </div>
    </div>
    <script>
        // ==== 用户信息与全局变量 ====
        const user = getCurrentUser();
        if (!user) {
            window.location.href = '/static/index.html';
        }
        const userId = user.userId;
        const userName = user.username;
        function getRoomId() {
            const url = new URL(window.location.href);
            return url.searchParams.get('room_id');
        }
        const roomId = getRoomId();
        document.addEventListener('DOMContentLoaded', function() {
            initRoomOwnerActions(roomId, userId, 'delete-room-btn', '/static/index.html');
            // 通用房间用户管理
            initGameRoomUserManager({
                roomId,
                userId,
                userName,
                readyBtnId: 'ready-btn',
                playerCardIds: ['player1-card', 'player2-card'],
                playerNameIds: ['player1-name', 'player2-name'],
                playerStatusIds: ['player1-status', 'player2-status'],
                roomUserCountId: 'room-user-count',
                onAllReady: function(players) {
                    // 所有玩家准备好时的回调（可选）
                }
            });
        });
        // ==== WebSocket连接 ====
        const wsUrl = `ws://${location.host}/ws?user_id=${userId}&user_name=${encodeURIComponent(userName)}&room_id=${roomId}`;
        const ws = new WebSocket(wsUrl);
        ws.onopen = function() { console.log('WebSocket连接已建立'); };
        ws.onclose = function(event) { alert('连接已断开，请刷新页面重试'); };
        ws.onerror = function(error) { alert('WebSocket错误'); };
        // ==== 消息类型 ====
        const MessageTypeGameOp = 100;
        const MessageTypeGameState = 101;
        const MessageTypeReadyChanged = 102;
        // ==== 玩家信息渲染 ====
        let lastUserData = null;
        async function updateRoomUserCount() {
            try {
                const res = await fetch(`/api/rooms/users?room_id=${roomId}`);
                if (!res.ok) throw new Error(await res.text() || '获取房间信息失败');
                let users = await res.json();
                users = Array.isArray(users) ? users : [];
                const usersJson = JSON.stringify(users);
                if (lastUserData === usersJson) return;
                lastUserData = usersJson;
                document.getElementById('room-user-count').textContent = `房间人数：${users.length}`;
                users.sort((a, b) => a.join_time - b.join_time);
                renderUserInfoAndAllPlayers(users);
            } catch (error) {
                const gameStatus = document.getElementById('game-status');
                if (gameStatus) {
                    gameStatus.textContent = error.message || '获取房间信息失败';
                    gameStatus.style.color = 'red';
                }
            }
        }
        function renderUserInfoAndAllPlayers(users) {
            if (!Array.isArray(users)) return;
            // 玩家1
            const player1Card = document.getElementById('player1-card');
            const player1Name = document.getElementById('player1-name');
            const player1Status = document.getElementById('player1-status');
            if (users.length > 0) {
                const user1 = users[0];
                player1Name.textContent = user1.user_name || '未知玩家';
                const isReady1 = user1.ready || false;
                player1Status.textContent = isReady1 ? '已准备' : '未准备';
                player1Card.className = `player-card ${isReady1 ? 'ready' : 'not-ready'}`;
                player1Status.className = `status ${isReady1 ? 'ready' : ''}`;
                player1Card.setAttribute('data-user-id', user1.user_id);
            } else {
                player1Name.textContent = '等待加入...';
                player1Status.textContent = '未准备';
                player1Card.className = 'player-card not-ready';
                player1Status.className = 'status';
                player1Card.removeAttribute('data-user-id');
            }
            // 玩家2
            const player2Card = document.getElementById('player2-card');
            const player2Name = document.getElementById('player2-name');
            const player2Status = document.getElementById('player2-status');
            if (users.length > 1) {
                const user2 = users[1];
                player2Name.textContent = user2.user_name || '未知玩家';
                const isReady2 = user2.ready || false;
                player2Status.textContent = isReady2 ? '已准备' : '未准备';
                player2Card.className = `player-card ${isReady2 ? 'ready' : 'not-ready'}`;
                player2Status.className = `status ${isReady2 ? 'ready' : ''}`;
                player2Card.setAttribute('data-user-id', user2.user_id);
            } else {
                player2Name.textContent = '等待加入...';
                player2Status.textContent = '未准备';
                player2Card.className = 'player-card not-ready';
                player2Status.className = 'status';
                player2Card.removeAttribute('data-user-id');
            }
        }
        // ==== 准备按钮逻辑 ====
        let myReady = false;
        const readyBtn = document.getElementById('ready-btn');
        readyBtn.onclick = function() {
            myReady = !myReady;
            window.handleReadyStatusChange(userId, myReady);
            ws.send(JSON.stringify({
                type: MessageTypeGameOp,
                content: JSON.stringify({ op: 'ready', ready: myReady })
            }));
            setTimeout(() => { lastUserData = null; updateRoomUserCount(); }, 300);
            setTimeout(() => { lastUserData = null; updateRoomUserCount(); }, 1000);
        };
        // ==== WebSocket消息处理 ====
        window.handleReadyStatusChange = function(userId, isReady) {
            const player1Card = document.getElementById('player1-card');
            const player2Card = document.getElementById('player2-card');
            const player1Id = player1Card.getAttribute('data-user-id') || '';
            const player2Id = player2Card.getAttribute('data-user-id') || '';
            if (userId === player1Id) {
                const status = document.getElementById('player1-status');
                status.textContent = isReady ? '已准备' : '未准备';
                player1Card.className = `player-card ${isReady ? 'ready' : 'not-ready'}`;
                status.className = `status ${isReady ? 'ready' : ''}`;
                if (userId === window.userId) {
                    window.myReady = isReady;
                    readyBtn.textContent = isReady ? '取消准备' : '准备';
                }
            } else if (userId === player2Id) {
                const status = document.getElementById('player2-status');
                status.textContent = isReady ? '已准备' : '未准备';
                player2Card.className = `player-card ${isReady ? 'ready' : 'not-ready'}`;
                status.className = `status ${isReady ? 'ready' : ''}`;
                if (userId === window.userId) {
                    window.myReady = isReady;
                    readyBtn.textContent = isReady ? '取消准备' : '准备';
                }
            } else {
                lastUserData = null;
                updateRoomUserCount();
            }
        };
        ws.onmessage = function(e) {
            let msg = {};
            try { msg = JSON.parse(e.data); } catch (err) { return; }
            if (msg.type === 102) {
                try {
                    const data = JSON.parse(msg.content);
                    if (data && data.user_id && data.ready !== undefined) {
                        window.handleReadyStatusChange(data.user_id, data.ready);
                        return;
                    }
                } catch {}
            }
            if ([MessageTypeGameOp, MessageTypeGameState, MessageTypeReadyChanged].includes(msg.type)) {
                setTimeout(updateRoomUserCount, 100);
            }
        };
        // ==== 定时刷新房间用户 ====
        updateRoomUserCount();
        setInterval(updateRoomUserCount, 2000);
        // ==== 返回大厅弹窗 ====
        const backSelectBtn = document.getElementById('back-select-btn');
        const backModal = document.getElementById('back-modal');
        backSelectBtn.onclick = () => { backModal.style.display = 'flex'; };
        document.getElementById('close-modal').onclick = () => { backModal.style.display = 'none'; };
        document.getElementById('to-game-lobby').onclick = () => { safeCloseWSAndGo('/'); };
        document.getElementById('to-chat-lobby').onclick = () => { safeCloseWSAndGo('/'); };
        backModal.onclick = (e) => { if (e.target === backModal) backModal.style.display = 'none'; };
        // JS部分补充核心井字棋逻辑
        let gameState = {
            board: [
                [0,0,0],
                [0,0,0],
                [0,0,0]
            ], // 0空 1X 2O
            currentPlayer: 1, // 1X 2O
            status: 'waiting', // waiting, playing, gameover
            winner: null,
            lastMove: null
        };
        function initGame() {
            gameState.board = [ [0,0,0],[0,0,0],[0,0,0] ];
            gameState.currentPlayer = 1;
            gameState.status = 'waiting';
            gameState.winner = null;
            gameState.lastMove = null;
            renderBoard();
            document.getElementById('game-tip').textContent = '点击"开始游戏"按钮开始';
        }
        function renderBoard() {
            const canvas = document.getElementById('tictactoe-canvas');
            const ctx = canvas.getContext('2d');
            ctx.clearRect(0, 0, canvas.width, canvas.height);
            ctx.fillStyle = '#fff';
            ctx.fillRect(0, 0, canvas.width, canvas.height);
            ctx.strokeStyle = '#333';
            ctx.lineWidth = 2;
            for (let i = 1; i < 3; i++) {
                ctx.beginPath();
                ctx.moveTo(0, i*100);
                ctx.lineTo(300, i*100);
                ctx.stroke();
                ctx.beginPath();
                ctx.moveTo(i*100, 0);
                ctx.lineTo(i*100, 300);
                ctx.stroke();
            }
            for (let i = 0; i < 3; i++) for (let j = 0; j < 3; j++) {
                if (gameState.board[i][j] !== 0) {
                    ctx.save();
                    ctx.translate(j*100+50, i*100+50);
                    ctx.font = 'bold 60px sans-serif';
                    ctx.textAlign = 'center';
                    ctx.textBaseline = 'middle';
                    ctx.fillStyle = gameState.board[i][j] === 1 ? '#3b82f6' : '#ef4444';
                    ctx.fillText(gameState.board[i][j] === 1 ? 'X' : 'O', 0, 0);
                    ctx.restore();
                }
            }
            if (gameState.lastMove) {
                ctx.beginPath();
                ctx.arc(gameState.lastMove.y*100+50, gameState.lastMove.x*100+50, 10, 0, 2*Math.PI);
                ctx.fillStyle = '#f59e42';
                ctx.fill();
            }
            if (gameState.status === 'gameover') {
                ctx.fillStyle = 'rgba(0,0,0,0.5)';
                ctx.fillRect(0, 120, 300, 60);
                ctx.fillStyle = '#fff';
                ctx.font = '20px sans-serif';
                ctx.textAlign = 'center';
                ctx.fillText(gameState.winner ? (gameState.winner === 1 ? 'X获胜！' : 'O获胜！') : '平局', 150, 150);
            }
        }
        function checkWin() {
            const b = gameState.board;
            for (let i = 0; i < 3; i++) {
                if (b[i][0] && b[i][0] === b[i][1] && b[i][1] === b[i][2]) return b[i][0];
                if (b[0][i] && b[0][i] === b[1][i] && b[1][i] === b[2][i]) return b[0][i];
            }
            if (b[0][0] && b[0][0] === b[1][1] && b[1][1] === b[2][2]) return b[0][0];
            if (b[0][2] && b[0][2] === b[1][1] && b[1][1] === b[2][0]) return b[0][2];
            if (b.flat().every(v=>v!==0)) return 'draw';
            return null;
        }
        function handleBoardClick(e) {
            if (gameState.status !== 'playing') return;
            const rect = e.target.getBoundingClientRect();
            const x = Math.floor((e.clientY - rect.top) / 100);
            const y = Math.floor((e.clientX - rect.left) / 100);
            if (x<0||x>=3||y<0||y>=3||gameState.board[x][y]!==0) return;
            if (window.isMulti && gameState.currentPlayer !== window.myShape) return;
            doMove(x, y, true);
            if (window.isMulti) {
                ws.send(JSON.stringify({type: 100, content: JSON.stringify({op:'move',x,y})}));
            }
        }
        function doMove(x, y, local) {
            if (gameState.board[x][y] !== 0) return;
            gameState.board[x][y] = gameState.currentPlayer;
            gameState.lastMove = {x, y};
            const winner = checkWin();
            if (winner) {
                gameState.status = 'gameover';
                gameState.winner = winner === 'draw' ? null : winner;
                document.getElementById('game-tip').textContent = winner === 'draw' ? '平局！' : (winner === 1 ? 'X获胜！' : 'O获胜！');
            } else {
                gameState.currentPlayer = 3 - gameState.currentPlayer;
                document.getElementById('game-tip').textContent = (gameState.currentPlayer === 1 ? 'X' : 'O') + '落子';
            }
            renderBoard();
        }
        document.getElementById('tictactoe-canvas').onclick = handleBoardClick;
        document.getElementById('start-btn').classList.remove('hidden');
        document.getElementById('start-btn').onclick = function() {
            gameState.status = 'playing';
            document.getElementById('game-tip').textContent = (gameState.currentPlayer === 1 ? 'X' : 'O') + '落子';
            renderBoard();
            if (window.isMulti) ws.send(JSON.stringify({type: 100, content: JSON.stringify({op:'start'})}));
        };
        document.getElementById('restart-btn').onclick = function() {
            initGame();
            if (window.isMulti) ws.send(JSON.stringify({type: 100, content: JSON.stringify({op:'restart'})}));
        };
        // 多人/单人模式自动切换
        window.isMulti = false;
        window.myShape = 1;
        function updateMode(users) {
            if (users.length > 1) {
                window.isMulti = true;
                window.myShape = users[0].user_id === userId ? 1 : 2;
            } else {
                window.isMulti = false;
                window.myShape = 1;
            }
        }
    </script>
</body>
</html> 